//***********************************************
//Project Name               :
//File Name                  :
//Author                     :ZJL
//Date of Creation           :20190920
//Functional Description     :图像数据仿真
//              
//Revision History           :
//Change Log                 :
//***********************************************
`timescale 1ns/1ns
module tb_x2;
//------------------------------------------
// `define 1280_1024_30


// `ifdef 1280_1024_30
// 	parameter FRAME_RATE 		= 30;								//帧频
// 	parameter RES_WIDTH 		= 1280;								//分辨率：宽度
// 	parameter RES_HEIGHT 		= 1024;								//分辨率：高度
// `endif

// `else//def 320_256_50
// 	parameter FRAME_RATE 		= 50;								//帧频
// 	parameter RES_WIDTH 		= 320;								//分辨率：宽度
// 	parameter RES_HEIGHT 		= 256;								//分辨率：高度
// `endif


	parameter FRAME_RATE 		= 50;								//帧频
	parameter RES_WIDTH 		= 320;								//分辨率：宽度
	parameter RES_HEIGHT 		= 256;								//分辨率：高度
parameter PERIOD_50MHZ	 	= 20;								//50MHz
parameter LINE_BLANK 		= 50;								//消隐期周期数
parameter EXTRA_LINES 		= 10;								//多输出的行数
parameter FRAME_PERIOD 	= 1_000_000_000/FRAME_RATE;			//帧周期-‭16,666,666.66666667‬ns
parameter TOTAL_PIXEL 		= (RES_WIDTH + LINE_BLANK);			//多输出的行数-1330
parameter TOTAL_LINES 		= (RES_HEIGHT + EXTRA_LINES);		//多输出的行数-1040
parameter CNT_WAIT_TIME 	= (FRAME_PERIOD/20 - (TOTAL_PIXEL * TOTAL_LINES))/2;//多输出的行数
parameter TEMP1 		= FRAME_PERIOD/20;		//多输出的行数-1040
parameter TEMP2 		= TOTAL_PIXEL * TOTAL_LINES;		//多输出的行数-1040
parameter TEMP3 		= TEMP1 - TEMP2;		//多输出的行数-1040
//信号列表
reg	 				clk;		//clock
reg 				rst_n;		//reset @high voltage

reg					in_pulse;	//input signal
reg					i_start;	//to streamscale
wire 	[7:0]		o_data;		//data after scale
wire 				o_dvalid;	//data valid after scale
reg 	[16-1:0] 		cnt_x=0;	//counter for horizne
reg 	[9:0] 		cnt_y=0;	//counter for vertical
reg 				sync_x = 0;	//sync signal for horizne
reg 				sync_y = 0;	//sync signal for vertical
reg		[2:0] 		zoom_para;	//
wire 				fifo_wr;
wire 	[7:0]		data_tmp;
integer 			i;			//counter for random task
reg 	[0:0]		rand_data;	//random data out
integer 			N = 2;		//random seed
reg 	[7:0] 		reg_mem[0:320*256-1];	//! memory
integer 			addr;				//memory address

reg 	[1-1:0] 		field_rst;
wire 	[1-1:0] 		wait_done;
reg 	[1-1:0] 		flag_image;
//------------------------------------------

//系统时钟
initial
begin
	clk = 0;
	forever	#(PERIOD_50MHZ/2)
	clk = ~clk;
end

//------------------任务------------------------
//*任务：系统初始化
task task_sysinit;
begin
	in_pulse = 0;
	i_start = 0;
	field_rst = 0;
end
endtask

//*任务：Generate global reset
task task_reset;
begin
	rst_n = 0;
	repeat(2) @(negedge clk);
	rst_n = 1;
end
endtask

//产生帧复位信号
task task_field_rst;
begin
	@(posedge clk);
		field_rst = 1;
	@(posedge clk);
		field_rst = 0;
	#(FRAME_PERIOD);
	@(posedge clk);
		field_rst = 1;
	@(posedge clk);
		field_rst = 0;
end
endtask

//*任务：读取文件到内存
task load_data2mem;
begin
	$readmemh("lena.txt",reg_mem);
end
endtask

//*任务：读取一行数据
//task功能说明：先延时#(10000*3)，然后在时钟上升沿行计数器加一，重复321次，最后截取计数器1~320周期，共计320个像素
task generate_line;
	begin
		#(10000*3)
		cnt_x = 0;
		repeat(321) begin
			@ ( posedge clk ) begin
				cnt_x = cnt_x + 1;
			end
		sync_x = ( cnt_x >= 10'd1 && cnt_x <= 10'd320 ) ? 1 : 0;
		end
	end
endtask

//*任务：读取一帧数据
task generate_frame;
	begin
		repeat(321) begin//x行数
			generate_line;
		end
	end
endtask

//task of generate random bit signal
//*任务：产生随机数
task task_rand_bit;
begin
	begin
		for( i = 0; i < 255; i=i+1 )begin
			@( posedge clk );
				rand_data = { $random } % N;//随机数取值范围[0,N-1]
		end
	end
end
endtask

//-----------------存储器地址------------------------
//生成存储器地址
always @ (posedge clk)begin
	if(!rst_n) begin
		addr <= 0;
	end
	else if( sync_x )begin
		addr <= addr +1;
	end
end
assign data_tmp = reg_mem[addr];//从内存中读出数据
//------------------行计数-----------------------
wire        [1-1:0]         wait_time_add;
reg        [1-1:0]         en_cnt_wait_time;
reg        [32-1:0]        cnt_wait_time;
assign     wait_time_add = field_rst;
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		cnt_wait_time        <=        'd0;
	end
	else if( en_cnt_wait_time )begin//只有在有效才计数
		cnt_wait_time        <=        cnt_wait_time + 'd1;
	end
	else begin
		cnt_wait_time        <=        'd0;
	end
end
		
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		en_cnt_wait_time        <=        'd0;
	end
	else if( cnt_wait_time == CNT_WAIT_TIME - 1)begin//结束计数条件
		en_cnt_wait_time        <=        'd0;
	end
	else if( wait_time_add )begin        //开始计数条件
		en_cnt_wait_time        <=        'd1;
	end
	else begin
		en_cnt_wait_time        <=        en_cnt_wait_time;
	end
end
assign wait_done = ( cnt_wait_time == CNT_WAIT_TIME - 1);

reg [12-1:0] hcnt;
reg [12-1:0] vcnt;
wire [1-1:0] h_valid;
wire [1-1:0] v_valid;
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		flag_image        <=        'd0;
	end
	else if( vcnt == RES_HEIGHT-1 && hcnt == RES_WIDTH-1 )begin//结束计数条件
		flag_image        <=        'd0;
	end
	else if( wait_done )begin        //开始计数条件
		flag_image        <=        'd1;
	end
	else begin
		flag_image        <=        flag_image;
	end
end
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		hcnt        <=        'd0;
	end
	else if( flag_image )begin//结束计数条件
		if( hcnt ==  TOTAL_PIXEL-1)
			hcnt        <=        'd0;
		else
			hcnt        <=        hcnt + 'd1;
	end
	else begin
		hcnt        <=        'd0;
	end
end
assign h_valid = ( flag_image && hcnt<RES_WIDTH );
assign v_valid = ( flag_image && vcnt<RES_HEIGHT );
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		vcnt        <=        'd0;
	end
	else if( flag_image )begin//结束计数条件
		if( hcnt ==  TOTAL_PIXEL-1)
			vcnt        <=        vcnt + 'd1;
		else
			vcnt        <=        vcnt;
	end
	else begin
		vcnt        <=        'd0;
	end
end


// wire        [1-1:0]         x_add;
// reg        [1-1:0]         en_cnt_x;
// parameter                  CNT_X = 'd90;
// assign     x_add = 
// always @ ( posedge clk ) begin
// 	if( ~rst_n ) begin
// 		cnt_x        <=        'd0;
// 	end
// 	else if( en_cnt_x )begin//只有在有效才计数
// 		cnt_x        <=        cnt_x + 'd1;
// 	end
// 	else begin
// 		cnt_x        <=        'd0;
// 	end
// end
		
// always @ ( posedge clk ) begin
// 	if(~rst_n) begin
// 		en_cnt_x        <=        'd0;
// 	end
// 	else if( cnt_x == CNT_X - 1)begin//结束计数条件
// 		en_cnt_x        <=        'd0;
// 	end
// 	else if( x_add )begin        //开始计数条件
// 		en_cnt_x        <=        'd1;
// 	end
// 	else begin
// 		en_cnt_x        <=        en_cnt_x;
// 	end
// end


always @ (posedge clk)begin
	if(!rst_n) begin
		cnt_y <= 10'd0;
	end
	else if( cnt_y == 10'd256 )begin
		cnt_y <=  10'd256;
	end
	else if( sync_x && cnt_x == 10'd320 )begin
		cnt_y <= cnt_y +1;
	end
	else
		cnt_y <= cnt_y;
end
always @ (*)begin
	if(!rst_n) begin
		sync_y <= 1'd0;
	end
	else if( cnt_x > 10'd0 && cnt_y< 10'd256 )begin
		sync_y <= 1'd1;
	end
	else if( cnt_y== 10'd256 )begin
		sync_y <= 1'd0;
	end
	else
		sync_y <= sync_y;
end
assign fifo_wr = sync_x && sync_y;//! 同步信号

//----------------------系统初始化------------------------
initial
begin
	task_sysinit;
	task_reset;
	zoom_para = 3'd1;
	#5000 i_start = 1;
	#(PERIOD_50MHZ*2)
	i_start = 0;
	// generate_frame;
	#100
	@ ( posedge clk )
		in_pulse = 1;
	@ ( posedge clk )
		in_pulse = 0;
	task_field_rst;
end
//----------------------系统函数------------------------
//将仿真数据o_data写入外部TXT文件中(x1.txt)
// integer file_df;
// initial begin
// 	//文件放置在"工程目录\simulation\modelsim"路径下
// 	file_df = $fopen("x1.txt");
// 	if(!file_df)begin
// 		$display("could not open file!");
// 		$finish;
// 	end
// end
// always @(posedge clk) begin
// 	if( o_dvalid )//一帧图像数据
// 		$fdisplay(file_df,"%d",o_data);
// end

// initial begin
// 	// $dumpfile("test.vcd");
// 	// $dumpvars();
// end

//----------------------模块例化------------------------
// x_top inst_x_top(
// 	.clk		( clk ),
// 	.rst_n		( rst_n ),
// 	.i_data		( data_tmp ),
// 	.i_fifo_wr	(fifo_wr),
// 	.i_start	(i_start),
// 	.o_data		( o_data ),
// 	.o_dvalid	(o_dvalid),
// 	.i_zoom_para(zoom_para)
// );
//----------------------------------------------

endmodule
